﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Office.OneNote;
using System.Xml.Linq;

namespace OneNoteFramework.Tests.Infrastructure
{
    [TestClass]
    public class SerializerTests
    {
        [TestMethod]
        public void SerializeAttributesOnly()
        {
            AttributeOnlyObject obj = new AttributeOnlyObject()
            {
                First = "first!!!",
                Second = "second!!!"
            };

            XElement element = OneNoteSchema.CreateElement(obj);
            Assert.IsNotNull(element);
            Assert.AreEqual("AOO", element.Name.LocalName);

            OneNoteSchema.SerializeAllProperties(obj, element);

            AssertAttributeOnlyObject(obj, element);
        }

        [TestMethod]
        public void SerializeComplexObject()
        {
            ComplexObject co = new ComplexObject();
            co.ComplexProp.First = "co-first";
            co.ComplexProp.Second = "co-second";

            XElement element = OneNoteSchema.CreateElement(co);
            Assert.IsNotNull(element);
            Assert.AreEqual("CO", element.Name.LocalName);

            OneNoteSchema.SerializeAllProperties(co, element);

            XElement elAoo = element.Element(OneNoteSchema.GetElementName(typeof(AttributeOnlyObject)));
            AssertAttributeOnlyObject(co.ComplexProp, elAoo);
        }

        [TestMethod]
        public void SerializeCDataObject()
        {
            const string Text = "CCCC <<DDDD &&& AAAA>> TTTT]]> AAAA ";
            CDataCallback cdc =  new CDataCallback();
            cdc.Value = Text;

            XElement element = OneNoteSchema.Serialize(cdc);
            Assert.IsNotNull(element);

            Assert.AreEqual("CDataElement", element.Name.LocalName);
            
            XCData cdata = element.FirstNode as XCData;
            Assert.IsNotNull(cdata);
            Assert.AreEqual(Text, cdata.Value);
        }

        private void AssertAttributeOnlyObject(AttributeOnlyObject aoo, XElement element)
        {
            Assert.IsNotNull(aoo);
            Assert.IsNotNull(element);

            XAttribute aFirst = element.Attribute(XName.Get("First"));
            XAttribute aSecond = element.Attribute(XName.Get("Second"));

            Assert.IsNotNull(aFirst);
            Assert.IsNotNull(aSecond);

            Assert.AreEqual(aoo.First, aFirst.Value);
            Assert.AreEqual(aoo.Second, aSecond.Value);
        }

        [OneNoteXmlElement("CDataElement")]
        internal class CDataCallback : OneNoteObject, IOneNoteSchemaCallback
        {
            public CDataCallback()
	        {
	        }

            public string Value 
            {
                get;
                set; 
            }

            public void Deserialize(XElement element)
            {
                Value = ((XCData)(element.FirstNode)).Value;
            }

            public void Serialize(XElement element)
            {
                element.RemoveAll();
                element.Add(new XCData(Value));
            }
        }

        [OneNoteXmlElement("CO")]
        internal class ComplexObject : OneNoteObject
        {
            public static readonly OneNoteProperty ComplexPropProperty = OneNoteProperty.Register(
                "ComplexProp", typeof(AttributeOnlyObject), typeof(ComplexObject),
                DefaultValueProvider.NewInstance<AttributeOnlyObject>());

            public AttributeOnlyObject ComplexProp
            {
                get { return GetValue<AttributeOnlyObject>(ComplexPropProperty); }
            }
        }

        [OneNoteXmlElement("AOO")]
        internal class AttributeOnlyObject : OneNoteObject
        {
            public static readonly OneNoteProperty FirstProperty = OneNoteProperty.Register(
                "First", typeof(String), typeof(AttributeOnlyObject));

            public static readonly OneNoteProperty SecondProperty = OneNoteProperty.Register(
                "Second", typeof(String), typeof(AttributeOnlyObject));

            public String First
            {
                get { return GetValue<String>(FirstProperty); }
                set { SetValue(FirstProperty, value); }
            }

            public String Second
            {
                get { return GetValue<String>(SecondProperty); }
                set { SetValue(SecondProperty, value); }
            }

        }
    }
}
